home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
mint
/
mint110s.zoo
/
realloc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-16
|
7KB
|
277 lines
/*
* Copyright 1992 Atari Corporation.
* All rights reserved.
*/
#include "mint.h"
/* macro for testing whether a memory region is free */
#define ISFREE(m) ((m)->links == 0)
/*
* long
* realloc_region(MEMREGION *reg, long newsize):
* attempt to resize "reg" to the indicated size. If newsize is
* less than the current region size, the call always
* succeeds; otherwise, we look for free blocks next to the
* region, and try to merge these.
*
* If newsize == -1L, simply returns the maximum size that
* the block could be allocated to.
*
* Returns: the (physical) address of the new bottom of the
* region, or 0L if the resize attempt fails.
*
* NOTES: if reg == 0, this call does a last-fit allocation
* of memory of the requested size, and returns a MEMREGION *
* (cast to a long) pointing at the last region that works
*
* This call works ONLY in the "core" memory region (aka ST RAM)
* and only on non-shared text regions.
*/
long
realloc_region(reg, newsize)
MEMREGION *reg;
long newsize;
{
MMAP map;
MEMREGION *m,*prevptr;
long oldsize, trysize;
if (newsize != -1L)
newsize = ROUND(newsize);
oldsize = reg->len;
if ( reg == 0 || (reg->mflags & M_CORE))
map = core;
else {
return 0;
}
/* last fit allocation: this is pretty straightforward,
* we just look for the last block that would work
* and slice off the top part of it.
* problem: we don't know what the "last block that would fit"
* is for newsize == -1L, so we look for the biggest block
*/
if (reg == 0) {
MEMREGION *lastfit = 0;
MEMREGION *newm = new_region();
for (m = *map; m; m = m->next) {
if (ISFREE(m)) {
if (newsize == -1L && lastfit
&& m->len >= lastfit->len)
lastfit = m;
else if (m->len >= newsize)
lastfit = m;
}
}
if (!lastfit)
return 0;
if (newsize == -1L)
return lastfit->len;
/* if the sizes match exactly, we save a bit of work */
if (lastfit->len == newsize) {
if (newm) dispose_region(newm);
lastfit->links++;
mark_region(lastfit, PROT_G);
return (long)lastfit;
}
if (!newm) return 0; /* can't get a new region */
/* chop off the top "newsize" bytes from lastfit */
/* and add it to "newm" */
lastfit->len -= newsize;
newm->loc = lastfit->loc + lastfit->len;
newm->len = newsize;
newm->mflags = lastfit->mflags & M_MAP;
newm->links++;
newm->next = lastfit->next;
lastfit->next = newm;
mark_region(newm, PROT_G);
return (long)newm;
}
/* check for trivial resize */
if (newsize == oldsize) {
return reg->loc;
}
/*
* find the block just before ours
*/
if (*map == reg)
prevptr = 0;
else {
prevptr = *map;
while (prevptr->next != reg && prevptr) {
prevptr = prevptr->next;
}
}
/*
* If we're shrinking the block, there's not too much to
* do (we just free the first "oldsize-newsize" bytes by
* creating a new region, putting those bytes into it,
* and freeing it).
*/
if (newsize < oldsize && newsize != -1L) {
if (prevptr && ISFREE(prevptr)) {
/* add this memory to the previous free region */
prevptr->len += oldsize - newsize;
reg->loc += oldsize - newsize;
reg->len -= oldsize - newsize;
mark_region(prevptr, PROT_I);
mark_region(reg, PROT_G);
return reg->loc;
}
/* make a new region for the freed memory */
m = new_region();
if (!m) {
/* oops, couldn't get a region -- we lose */
/* punt and pretend we succeeded; after all,
* we have enough memory!
*/
return reg->loc;
}
/* set up the fake region */
m->links = 0;
m->mflags = reg->mflags & M_MAP;
m->loc = reg->loc;
m->len = oldsize - newsize;
/* update our region (it's smaller now) */
reg->loc += m->len;
reg->len -= m->len;
/* link the region in just ahead of us */
if (prevptr)
prevptr->next = m;
else
*map = m;
m->next = reg;
mark_region(m, PROT_I);
mark_region(reg, PROT_G);
return reg->loc;
}
/* OK, here we have to grow the region: to do this, we first try adding
* bytes from the region after us (if any) and then the region before
* us
*/
trysize = oldsize;
if (reg->next && ISFREE(reg->next) &&
(reg->loc + reg->len == reg->next->loc)) {
trysize += reg->next->len;
}
if (prevptr && ISFREE(prevptr) &&
(prevptr->loc + prevptr->len == reg->loc)) {
trysize += prevptr->len;
}
if (trysize < newsize) {
FORCE("realloc_region: need %ld bytes, only have %ld", trysize, newsize);
return 0; /* not enough room */
}
if (newsize == -1L) /* size inquiry only?? */
return trysize;
/* BUG: we can be a bit too aggressive at sweeping up
* memory regions coming after our region; on the other
* hand, unless something goes seriously wrong there
* never should *be* any such regions
*/
if (reg->next && ISFREE(reg->next) &&
(reg->loc + reg->len == reg->next->loc)) {
MEMREGION *foo = reg->next;
reg->len += foo->len;
reg->next = foo->next;
dispose_region(foo);
mark_region(reg, PROT_G);
if (reg->len >= newsize)
return reg->loc;
oldsize = reg->len;
}
assert(prevptr && ISFREE(prevptr) &&
prevptr->loc + prevptr->len == reg->loc);
if (newsize > oldsize) {
reg->loc -= (newsize - oldsize);
reg->len += (newsize - oldsize);
prevptr->len -= (newsize - oldsize);
if (prevptr->len == 0) {
/* hmmm, we used up the whole region -- we must dispose of the
* region descriptor
*/
if (*map == prevptr)
*map = prevptr->next;
else {
for (m = *map; m; m = m->next) {
if (m->next == prevptr) {
m->next = prevptr->next;
break;
}
}
}
dispose_region(prevptr);
}
mark_region(reg, PROT_G);
}
/* finally! we return the new starting address of "our" region */
return reg->loc;
}
/*
* s_realloc emulation: this isn't quite perfect, since the memory
* used up by the "first" screen will be wasted (we could recover
* this if we knew the screen start and size, and manually built
* a region for that screen and linked it into the "core" map
* (probably at the end))
* We must always ensure a 256 byte "pad" area is available after
* the screen (so that it doesn't abut the end of memory)
*/
MEMREGION *screen_region = 0;
#define PAD 256L
long ARGS_ON_STACK
s_realloc(size)
long size;
{
long r;
TRACE(("s_realloc(%ld)", size));
if (size != -1L)
size += PAD;
if (!screen_region) {
r = realloc_region(screen_region, size);
if (size == -1L) { /* inquiry only */
TRACE(("%ld bytes max srealloc", r-PAD));
return r - PAD;
}
screen_region = (MEMREGION *)r;
if (!screen_region) {
DEBUG(("s_realloc: no screen region!!"));
return 0;
}
return screen_region->loc;
}
r = realloc_region(screen_region, size);
if (size == -1L) {
return r - PAD;
} else {
return r;
}
}